package com.mycode.prototype05;

import com.mycode.prototype05.model.ConcretePrototype;
import com.mycode.prototype05.model.Prototype;
import com.mycode.prototype05.resolve.WeeklyLog;

/**
 * 原型模式：通过一个原型对象克隆出多个一摸一样的对象，该模式称之为原型模式
 * 主要优点：
 *     1、当创建新的对象实例较为复杂时，使用原型模型可以简化对象的创建过程。通过复制一个已有实例可以提高新实例的创建效率
 *     2、扩展性好。可以通过配置文件进行扩展
 *     3、简化了创建结构。通过克隆方式实现产品复制，无需专门的工厂类
 *     4、深克隆的方式保存对象的状态，可以辅助实现撤销操作
 * 主要缺点：
 *     1、需要为每一个类配备一个克隆方法，如果有改动需要修改克隆源代码，违背了开闭原则、
 *     2、实现深克隆时需要编写较为复杂的代码，而且当对象之间存在多重的嵌套引用时，为了实现深克隆，每一层对象对应的类都必须支持深克隆，实现比较麻烦
 * 适用场景：
 *     1、创建新对象成本较大（初始化占用较长时间，占用太多的CPU资源或网络资源），新对象可以通过原型模式对已有对象进行复制获得
 *     2、系统要保存对象的状态，而对象的状态变化很小，或者对象本身占用内存较少时，可以使用原型模式配合备忘录模式
 *     3、需要避免使用分层次的工厂类来创建分层次的对象，并且类的实例对象只有一个或很少的几个组合状态，通过复制原型对象得到新实例可能比使用构造函数创建一个新实例更加方便
 */
public class Bootstrap {

    public static void main(String[] args) {
        // Prototype prototype = new ConcretePrototype();
        // prototype.setAttr("Sunny");
        // Prototype clone = prototype.clone();
        // System.out.println(clone != prototype);
        // System.out.println(clone.getClass() == prototype.getClass());
        // System.out.println(clone.equals(prototype));

        // 创建原型对象
        WeeklyLog log = new WeeklyLog();
        log.setName("张三");
        log.setDate("第12周");
        log.setContent("这周工作很忙，每天都要加班");

        System.out.println("******* 周报 *******");
        System.out.println("周次：" + log.getDate());
        System.out.println("姓名：" + log.getName());
        System.out.println("内容：" + log.getContent());

        System.out.println("----------------------");

        WeeklyLog newLog;
        // 调用克隆方法创建克隆对象
        newLog = log.clone();
        newLog.setDate("第13周");
        System.out.println("******* 周报 *******");
        System.out.println("周次：" + newLog.getDate());
        System.out.println("姓名：" + newLog.getName());
        System.out.println("内容：" + newLog.getContent());

        System.out.println("----------------------");

        System.out.println(log == newLog);
        // true
        System.out.println(log.getName() == newLog.getName());
        System.out.println(log.getDate() == newLog.getDate());
        // true
        System.out.println(log.getContent() == newLog.getContent());
        /**
         *
         */

    }
}
